/**
 * grayrabbit Inc.
 * Copyright (c) 2011-2012 All Rights Reserved.
 */
package com.grayrabbit.slacker.start;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;

import com.grayrabbit.slacker.config.Configuration;
import com.grayrabbit.slacker.config.GenerateConfig;
import com.grayrabbit.slacker.config.provider.XmlConfigParseProvider;
import com.grayrabbit.slacker.constant.ConfigConstant;
import com.grayrabbit.slacker.dababase.DatabaseProvider;
import com.grayrabbit.slacker.factory.DatabaseProdiverFactory;
import com.grayrabbit.slacker.file.TemplateFileProvider;
import com.grayrabbit.slacker.interfaces.CodeGenerate;
import com.grayrabbit.slacker.utils.TemplateProcessUtils;

/**
 * 启动代码生成处理
 * 
 * @author liyd
 * @version $Id: GenerateStarter.java, v 0.1 2012-5-11 上午9:29:20 liyd Exp $
 */
public class GenerateStarter {

    /** 日志对象 */
    private final static Logger                LOG        = Logger.getLogger(GenerateStarter.class);

    /** 表的列信息 key为表名 */
    private static Map<String, List<String[]>> columnsMap = new HashMap<String, List<String[]>>();

    /** 数据库操作对象 */
    private DatabaseProvider                   databaseProvider;

    /** 模板中需要替换的参数对象 */
    private Map<String, String>                modelMap   = new HashMap<String, String>();

    /**
     * 初始化资源
     */
    private void init() {

        //解析配置xml，初始化配置信息 存放在 Configuration
        XmlConfigParseProvider.xmlConfigInit();
    }

    /**
     * 生成代码
     */
    public void codeGenerate() {

        LOG.info("开始运行代码生成工具");
        init();

        //单个队列任务对象
        GenerateConfig generateConfig = null;

        while ((generateConfig = Configuration.pollGenerateConfig()) != null) {

            //清空参数对象
            modelMap.clear();

            LOG.debug("对表[" + generateConfig.getTableName() + "]的["
                      + generateConfig.getGenerateName() + "]任务进行生成");

            //从数据库获取表列信息
            generateConfig.setColumns(getColumns(generateConfig.getTableName()));

            //生成文件路径
            String targetFilePath = TemplateProcessUtils.getTargetFilePath(generateConfig);

            if (isFileExists(targetFilePath) && !generateConfig.getReplace()) {

                LOG.info("需要生成的文件已经存在且覆盖标识为false，跳过文件[" + targetFilePath + "]");

                //添加类信息
                addClassInfoByResult(generateConfig);

                continue;
            }

            //得到具体处理类
            CodeGenerate codeGenerate = (CodeGenerate) getClassInstance(generateConfig.getClazz());

            //构造生成代码
            codeGenerate.generate(generateConfig, modelMap);

            //生成代码文件
            generateFile(generateConfig, targetFilePath);

            //添加生成文件信息
            addClassInfoByResult(generateConfig);

            LOG.debug("对表[" + generateConfig.getTableName() + "]的["
                      + generateConfig.getGenerateName() + "]任务生成完毕");
        }
        LOG.info("代码生成工具运行完毕");
    }

    /**
     * 生成文件
     * 
     * @param generateConfig
     * @param targetFilePath
     */
    private void generateFile(GenerateConfig generateConfig, String targetFilePath) {

        //模板文件
        String vm = TemplateProcessUtils.getTemplate(generateConfig);

        //渲染参数
        vm = renderVM(vm, modelMap);

        //如果指定了单独生成的路径
        if (StringUtils.isNotBlank(generateConfig.getTargetFilePath())) {

            targetFilePath = generateConfig.getTargetFilePath();

            //单独生成的，需要再次判断
            if (isFileExists(targetFilePath) && !generateConfig.getReplace()) {

                LOG.info("需要生成的文件已经存在且覆盖标识为false，跳过文件[" + targetFilePath + "]");

                return;
            }
        }
        //生成文件
        TemplateProcessUtils.writeFile(targetFilePath, vm);

    }

    /**
     * 添加生成文件信息
     * 
     * @param generateConfig
     */
    private void addClassInfoByResult(GenerateConfig generateConfig) {

        //指定的生成文件信息
        String fileInfo = generateConfig.getTargetFilePath();

        if (StringUtils.isBlank(fileInfo)) {
            //获取默认生成信息
            fileInfo = TemplateProcessUtils.getQualifiedClassName(generateConfig);
        }

        //添加生成的实体类信息
        Configuration.addClass(generateConfig.getTableName() + generateConfig.getGenerateName(),
            fileInfo);
    }

    /**
     * 处理模板中的参数
     * 
     * @param vm
     * @param modelMap
     * @return
     */
    private String renderVM(String vm, Map<String, String> modelMap) {

        if (modelMap.size() == 0) {
            return vm;
        }

        for (Entry<String, String> modelEntry : modelMap.entrySet()) {

            vm = vm.replaceAll("\\$\\{" + modelEntry.getKey() + "\\}", modelEntry.getValue());
        }
        return vm;
    }

    /**
     * 根据表名获取列信息
     * 
     * @param tableName
     * @return
     */
    private List<String[]> getColumns(String tableName) {

        if (columnsMap.get(tableName) != null) {

            return columnsMap.get(tableName);
        }

        //databaseProvider工厂
        DatabaseProdiverFactory databaseProdiverFactory = new DatabaseProdiverFactory(
            ConfigConstant.DATABASE_TYPE);

        databaseProvider = databaseProdiverFactory.builerDatabaseProvider();

        //从数据库获取表列信息
        List<String[]> columns = databaseProvider.getMetaData(tableName);

        columnsMap.put(tableName, columns);

        return columns;
    }

    /**
     * 根据类名创建类实例
     * 
     * @param className
     * @return
     */
    private Object getClassInstance(String className) {

        Object obj = null;
        try {
            obj = Class.forName(className).newInstance();
        } catch (Exception e) {
            LOG.error("用反射方式初始化类对象失败", e);
        }
        return obj;
    }

    /***
     * 判断文件是否已经存在
     * 
     * @param targetFilePath
     * @return
     */
    private boolean isFileExists(String targetFilePath) {

        return TemplateFileProvider.isFileExists(targetFilePath);
    }

}
